﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using MementoClient.Classes;
using MementoClientConnectorInterfaces;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using MementoClient.Interfaces;
using FluentAssertions;

namespace MementoWeb.Tests.MementoClient
{
    [TestClass]
    public class UserTasksRetrieverTest
    {
        [TestMethod]
        public void GetTasksForUser_CallsRetrieveOnClientConnectorRetriever()
        {
            var clientConnectorRetrieverMock = new Mock<IClientConnectorRetriever>();
            var userTasksRetriver = new UserTasksRetriever(clientConnectorRetrieverMock.Object);

            userTasksRetriver.GetTasksForUser("");

            clientConnectorRetrieverMock.Verify(c => c.Retrieve());
        }

        [TestMethod]
        public void GetTasksForUser_CallsGetConfigurationsOnOnEachClientConnector()
        {
            var clientConnectorRetrieverMock = new Mock<IClientConnectorRetriever>();
            var clientConnectorMock = new Mock<IMementoClientConnector>();
            var clientConnectorMock2 = new Mock<IMementoClientConnector>();
            clientConnectorMock.Setup(c => c.GetTasksForUser(It.IsAny<string>(), "TheName")).Returns(new List<Task>());
            clientConnectorMock2.Setup(c => c.GetTasksForUser(It.IsAny<string>(), "TheName")).Returns(new List<Task>());
            clientConnectorMock.Setup(c => c.GetConfigurations()).Returns(new List<TaskSourceSystemConfiguration>());
            clientConnectorMock2.Setup(c => c.GetConfigurations()).Returns(new List<TaskSourceSystemConfiguration>());

            clientConnectorRetrieverMock.Setup(r => r.Retrieve()).Returns(new[]
                                                                              {
                                                                                  clientConnectorMock.Object,
                                                                                  clientConnectorMock2.Object
                                                                              });
            var userTasksRetriver = new UserTasksRetriever(clientConnectorRetrieverMock.Object);

            // ReSharper disable ReturnValueOfPureMethodIsNotUsed
            userTasksRetriver.GetTasksForUser("TheName").ToList();
            // ReSharper restore ReturnValueOfPureMethodIsNotUsed

            clientConnectorMock.Verify(c => c.GetConfigurations());
            clientConnectorMock2.Verify(c => c.GetConfigurations());
        }

        [TestMethod]
        public void GetTasksForUser_CallsGetTasksForUserOnEachClientConnectorAndForEachConfiguration()
        {
            var clientConnectorRetrieverMock = new Mock<IClientConnectorRetriever>();
            var clientConnectorMock = new Mock<IMementoClientConnector>();
            var clientConnectorMock2 = new Mock<IMementoClientConnector>();
            var clientConnectorConfigurations = new List<TaskSourceSystemConfiguration> 
                        {
                            new TaskSourceSystemConfiguration {UniqueID = "10"}, 
                            new TaskSourceSystemConfiguration {UniqueID = "11"}
                        };
            var clientConnectorConfigurations2 = new List<TaskSourceSystemConfiguration> 
                        {
                            new TaskSourceSystemConfiguration {UniqueID = "12"}, 
                        };
            clientConnectorMock.Setup(c => c.GetConfigurations()).Returns(clientConnectorConfigurations);
            clientConnectorMock2.Setup(c => c.GetConfigurations()).Returns(clientConnectorConfigurations2);
            clientConnectorMock.Setup(c => c.GetTasksForUser("10", "TheName")).Returns(new List<Task>());
            clientConnectorMock.Setup(c => c.GetTasksForUser("11", "TheName")).Returns(new List<Task>());
            clientConnectorMock2.Setup(c => c.GetTasksForUser("12", "TheName")).Returns(new List<Task>());

            clientConnectorRetrieverMock.Setup(r => r.Retrieve()).Returns(new[]
                                                                              {
                                                                                  clientConnectorMock.Object,
                                                                                  clientConnectorMock2.Object
                                                                              });
            var userTasksRetriver = new UserTasksRetriever(clientConnectorRetrieverMock.Object);

// ReSharper disable ReturnValueOfPureMethodIsNotUsed
            userTasksRetriver.GetTasksForUser("TheName").ToList();
// ReSharper restore ReturnValueOfPureMethodIsNotUsed

            clientConnectorMock.VerifyAll();
            clientConnectorMock2.VerifyAll();
        }

        [TestMethod]
        public void GetTasksForUser_IfNoConfigurationsAreReturned_DoesNotCallGetTasksForUser()
        {
            var clientConnectorRetrieverMock = new Mock<IClientConnectorRetriever>();
            var clientConnectorMock = new Mock<IMementoClientConnector>();
            clientConnectorMock.Setup(c => c.GetTasksForUser(It.IsAny<string>(), "TheName")).Returns(new List<Task>());
            clientConnectorMock.Setup(c => c.GetConfigurations()).Returns(new List<TaskSourceSystemConfiguration>());
           
            clientConnectorRetrieverMock.Setup(r => r.Retrieve()).Returns(new[]
                                                                              {
                                                                                  clientConnectorMock.Object
                                                                              });
            var userTasksRetriver = new UserTasksRetriever(clientConnectorRetrieverMock.Object);

            // ReSharper disable ReturnValueOfPureMethodIsNotUsed
            userTasksRetriver.GetTasksForUser("TheName").ToList();
            // ReSharper restore ReturnValueOfPureMethodIsNotUsed

            clientConnectorMock.Verify(c => c.GetTasksForUser(It.IsAny<string>(), It.IsAny<string>()), Times.Never());
        }

        [TestMethod]
        public void GetTasksForUser_AggregatesReturnedTasksFromEachConnector()
        {
            var clientConnectorRetrieverMock = new Mock<IClientConnectorRetriever>();
            var clientConnectorMock = new Mock<IMementoClientConnector>();
            var clientConnectorMock2 = new Mock<IMementoClientConnector>();
            var clientConnectorConfigurations = new List<TaskSourceSystemConfiguration> 
                        {
                            new TaskSourceSystemConfiguration {UniqueID = "10"}, 
                            new TaskSourceSystemConfiguration {UniqueID = "11"}
                        };
            var clientConnectorConfigurations2 = new List<TaskSourceSystemConfiguration> 
                        {
                            new TaskSourceSystemConfiguration {UniqueID = "12"}, 
                        };
            clientConnectorMock.Setup(c => c.GetConfigurations()).Returns(clientConnectorConfigurations);
            clientConnectorMock2.Setup(c => c.GetConfigurations()).Returns(clientConnectorConfigurations2);
            var task1 = new Task();
            var task2 = new Task();
            var task3 = new Task();
            clientConnectorMock.Setup(c => c.GetTasksForUser("10", "TheName")).Returns(new List<Task> { task1});
            clientConnectorMock.Setup(c => c.GetTasksForUser("11", "TheName")).Returns(new List<Task> { task2});
            clientConnectorMock2.Setup(c => c.GetTasksForUser("12", "TheName")).Returns(new List<Task> { task3});

            clientConnectorRetrieverMock.Setup(r => r.Retrieve()).Returns(new[]
                                                                              {
                                                                                  clientConnectorMock.Object,
                                                                                  clientConnectorMock2.Object
                                                                              });
            var userTasksRetriver = new UserTasksRetriever(clientConnectorRetrieverMock.Object);

            var actualTasks = userTasksRetriver.GetTasksForUser("TheName").ToList();

            var expectedTasks = new [] {task1, task2, task3};
            actualTasks.Should().BeEquivalentTo(expectedTasks);
        }

        [TestMethod]
        public void GetTasksForUser_IncludesConfigurationUniqueIDInTaskIDandProjectID()
        {
            var clientConnectorRetrieverMock = new Mock<IClientConnectorRetriever>();
            var clientConnectorMock = new Mock<IMementoClientConnector>();
            var clientConnectorConfigurations = new List<TaskSourceSystemConfiguration> 
                        {
                            new TaskSourceSystemConfiguration {UniqueID = "10"}
                        };
            clientConnectorMock.Setup(c => c.GetConfigurations()).Returns(clientConnectorConfigurations);
            var task1 = new Task();
            task1.ProjectID = "100";
            task1.TaskID = "200";
            clientConnectorMock.Setup(c => c.GetTasksForUser("10", "TheName")).Returns(new List<Task> { task1 });

            clientConnectorRetrieverMock.Setup(r => r.Retrieve()).Returns(new[]
                                                                              {
                                                                                  clientConnectorMock.Object
                                                                              });
            var userTasksRetriver = new UserTasksRetriever(clientConnectorRetrieverMock.Object);

            var actualTasks = userTasksRetriver.GetTasksForUser("TheName").ToList();
            var actualTask = actualTasks.First();

            actualTask.ProjectID.Should().Be("10_100");
            actualTask.TaskID.Should().Be("10_200");
        }
    }
}
